#include <stdio.h>
#include <mqueue.h>     // POSIX 消息队列头文件
#include <fcntl.h>      // 文件控制常量
#include <stdlib.h>     // 标准库
#include <unistd.h>     // fork、sleep 等
#include <string.h>     // memset、strlen 等
#include <time.h>       // 定时相关

int main(void) {
    // step 1# 设置消息队列属性
    struct mq_attr my_mq_attr;
    my_mq_attr.mq_maxmsg = 10;     // 消息队列最大消息数
    my_mq_attr.mq_msgsize = 100;   // 单条消息最大字节数
    my_mq_attr.mq_flags = 0;       // 阻塞模式
    my_mq_attr.mq_curmsgs = 0;     // 当前消息数（只读）

    // step 2# 定义消息队列名称
    char *mq_name = "/father_son_mq";  // 消息队列名称（以 / 开头）

    // step 3# 创建消息队列，返回消息队列描述符
    mqd_t mqd = mq_open(mq_name, O_RDWR | O_CREAT, 0664, &my_mq_attr); // 可读写 + 创建
    if (mqd == -1) {
        perror("mq_open");     // 创建失败报错
        exit(EXIT_FAILURE);
    }

    // step 4# 创建子进程（生产者 / 消费者）
    pid_t pid = fork();
    if (pid < 0) {
        perror("fork");        // 创建失败报错
        exit(EXIT_FAILURE);
    }

    if (pid == 0) {
        // step 5# 子进程作为消费者，接收消息
        char read_buf[100];           // 接收缓冲区
        struct timespec time_info;    // 定时结构体
        ssize_t receive_res;          // 接收返回值状态

        for (int i = 0; i < 10; i++) {
            memset(read_buf, 0, 100);             // 清空缓冲区
            clock_gettime(CLOCK_REALTIME, &time_info);  // 获取当前时间
            time_info.tv_sec += 15;               // 设置超时为 15 秒

            // step 6# 接收消息（带超时）
            receive_res = mq_timedreceive(mqd, read_buf, 100, NULL, &time_info);
            if (receive_res == -1) {
                perror("mq_timedreceive");        // 接收失败
            } else {
                printf("子进程接收到数据: %s\n", read_buf);
            }
        }
    } else {
        // step 7# 父进程作为生产者，发送消息
        char send_buf[100];           // 发送缓冲区
        struct timespec time_info;    // 定时结构体
        ssize_t send_res;             // 发送返回值状态

        for (int i = 0; i < 10; i++) {
            memset(send_buf, 0, 100);                         // 清空缓冲区
            sprintf(send_buf, "父进程第%d次发送hello\n", i+1); // 构造消息内容
            clock_gettime(CLOCK_REALTIME, &time_info);        // 获取当前时间
            time_info.tv_sec += 15;                           // 设置超时为 15 秒

            // step 8# 发送消息（带超时）
            send_res = mq_timedsend(mqd, send_buf, strlen(send_buf), 0, &time_info);
            if (send_res == -1) {
                perror("mq_timedsend");       // 发送失败
            } else {
                printf("父进程发送了一条消息\n");
            }
            sleep(1); // 模拟发送间隔
        }
    }

    // step 9# 关闭消息队列（父子进程都要执行）
    close(mqd);  // 释放对消息队列的引用

    // step 10# 父进程删除消息队列（只需一次）
    if (pid > 0) {
        mq_unlink(mq_name);  // 删除消息队列对象
    }

    return 0;
}
